var app = app || {};

/*
app.Client stellt alle Funktionalitäten bereit um mit dem Server zu kommunizieren.
*/
app.Client = {

    serverURL: 'http://hippler.org:6789', // Kann hier zu hippler.org:8080 geändert werden, dann wird kein lokaler Server mehr benötigt

    /*
    Stellt die Verbindung zur Socket.IO her und bindet die Listener für die Serverevents ein.
    */
    init: function() {
        app.socket = io(app.Client.serverURL);
        app.socket.on('connect', function() {

            app.socket.emit('register', {
                uuid: app.Model.Data.getUUID(),
                currentTournament: app.Model.Data.getTournamentID()
            });

            app.socket.on('refreshTournamentList', app.Controller.recieveUpdateTournamentList);

            app.socket.on('gameover', app.Controller.gameover);

            app.socket.on('gamesChanged', app.Controller.refreshGames);

            app.socket.on('errorMessage', function(data) {
                app.View.Notifications.showMessageBox('Fehler', data.msg);
            });

        });
    },

    /* Sendet ein neues Turnier an den Server */
    newTournament: function(tournament, pwd) {
        $.ajax({
                url: app.Client.serverURL + '/tournament/new',
                type: 'POST',
                dataType: 'json',
                data: {
                    tournament: tournament,
                    pwd: pwd,
                    uuid: app.Model.Data.getUUID()
                },
                async: true
            })
            .done(function(data) {
                app.Controller.saveSuccess(data.id);
            })
            .fail(function(data) {
                app.View.Notifications.showMessageBanner('Turnier konnte nicht auf dem Server gespeichert werden: ' + data.responseText);
            });
    },

    /* Sendet dem Server, dass das aktuelle Turnier verlassen wird. */
    leaveTournament: function() {
        app.socket.emit('leaveTournament');
    },
    /* Löscht das Aktuelle Turnier auf dem Server */
    quitTournament: function() {
        $.ajax({
                url: app.Client.serverURL + '/tournament',
                type: 'DELETE',
                data: {
                    uuid: app.Model.Data.getUUID()
                },
                async: true,
            })
            .done(function(data) {
                app.View.Notifications.showMessageBanner('Turnier wurde auf dem Server gelöscht.');
            })
            .fail(function(msg) {
                app.View.Notifications.showMessageBanner('Turnier konnte nicht auf dem Server gelöscht werden: ' + data.responseText)
            });
    },
    /*
    Das Turnier mit der id id wird angefragt.
    Antwortet der server wird das Empfangene Turnier an den Controller zu weiterverabreiten gegeben.
    */
    joinTournament: function(id) {
        //Synchron
        $.ajax({
                url: app.Client.serverURL + '/tournament',
                type: 'POST',
                dataType: 'json',
                data: {
                    id: id,
                    uuid: app.Model.Data.getUUID()
                },
                async: false,
            })
            .done(function(data) {
                app.Controller.recieveTournament(data.tournament, data.id, data.isAdmin);
            })
            .fail(function(data) {
                app.View.Notifications.showMessageBox('Fehler bei dem Laden des Turniers', data.responseText);
            });
        //app.socket.emit('joinTournament', id);
    },
    /*
    Die geänderten Spiele werden an der Server gesendet
    */
    setScore: function(changes) {
        $.ajax({
                url: app.Client.serverURL + '/tournament',
                type: 'PUT',
                data: {
                    changes: changes,
                    uuid: app.Model.Data.getUUID()
                },
            })
            .done(function(data) {
                app.View.Notifications.showMessageBanner('Spieländerungen erfolgreich an Server gesendet.');
            })
            .fail(function(msg) {
                app.View.Notifications.showMessageBox('Fehler bei dem Senden der Spieländerungen an den Server', msg.responseText);
            });
    },

    /*
    Das Turnier mit der id: id und dem Passowrt: pwd wird zum bearbeiten angefragt.
    Antwortet der server wird das Empfangene Turnier an den Controller zu weiterverabreiten gegeben.
    */
    adminExistingTournament: function(id, pwd) {
        $.post(app.Client.serverURL + '/tournament/admin', {
            id: id,
            pwd: pwd,
            uuid: app.Model.Data.getUUID()
        }).done(function(data) {
            app.Controller.recieveTournament(data.tournament, id, data.isAdmin);
        }).fail(function(msg) {
            app.View.Notifications.showMessageBox('Fehler bei dem Laden des Turniers', msg.responseText);
        });
    },
    /*
    Die Aktuelle Turnierliste wird beim Server angrefragt
    */
    getTournamentList: function() {
        var list;
        $.ajax({
                url: app.Client.serverURL + '/tournamentList',
                type: 'POST',
                data: {
                    uuid: app.Model.Data.getUUID()
                },
                async: false,
            })
            .done(function(data) {
                list = data.list;
            })
            .fail(function(data) {
                list = false;
            });
        return list;
    }
};

/*
app.Model stellt Funktionalitäten für die Datenhaltung sowie für die TurnierLogik zuer Verfügung.
*/
app.Model = {
    /*
    TournamentLogic beinhaltet alle Funktionen, die die TurnierLogik übernehmen.
    */
    TournamentLogic: {
        /*
        Angegebenes Ergebnis wird im angegebenen Spiel gesetzt und im Tournier gespeichert.
        Alle Spiele, die durch das gesetzte Ergebnis angepasst wurden, werden als Liste zurück gegeben.
        */
        setScoreandGetChanges: function(gameIndex, score1, score2, tournament) {
            tournament = tournament || app.Model.Data.getClientTournament();
            if (!tournament ||
                tournament === "" ||
                gameIndex < 0 ||
                score1 < 0 ||
                score2 < 0 ||
                tournament.gameList[gameIndex].player1 === null ||
                tournament.gameList[gameIndex].player2 === null ||
                tournament.gameList[gameIndex].player1 === "" ||
                tournament.gameList[gameIndex].player2 === "" ||
                score1 === score2) {
                return false;
            }
            var changedGames = [],
                i,
                tmpGame,
                concat;
            tournament.gameList[gameIndex].scorePlayer1 = score1;
            tournament.gameList[gameIndex].scorePlayer2 = score2;
            changedGames.push({
                index: gameIndex,
                game: tournament.gameList[gameIndex]
            });
            if (tournament.gameList[gameIndex].source1 && tournament.gameList[gameIndex].source1.game > -1) {
                tournament.gameList[tournament.gameList[gameIndex].source1.game].editable = false;
                changedGames.push({
                    index: tournament.gameList[gameIndex].source1.game,
                    game: tournament.gameList[tournament.gameList[gameIndex].source1.game]
                });
            }
            if (tournament.gameList[gameIndex].source2 && tournament.gameList[gameIndex].source2.game > -1) {
                tournament.gameList[tournament.gameList[gameIndex].source2.game].editable = false;
                changedGames.push({
                    index: tournament.gameList[gameIndex].source2.game,
                    game: tournament.gameList[tournament.gameList[gameIndex].source2.game]
                });
            }
            for (i = 0; i < tournament.gameList.length; i++) {
                tmpGame = tournament.gameList[i];
                if (tmpGame.source1 !== null && tmpGame.source1 !== "" && tmpGame.source1.game == gameIndex) {
                    if (tmpGame.source1.asWinner) {
                        tmpGame.player1 = app.Model.TournamentLogic.getWinner(tournament.gameList[gameIndex]);
                    } else {
                        tmpGame.player1 = app.Model.TournamentLogic.getLoser(tournament.gameList[gameIndex]);
                    }
                    if (tmpGame.player1 > -1 && tmpGame.player1 != null && tmpGame.player2 > -1 && tmpGame.player2 != null) {
                        tmpGame.editable = true;
                    }
                    changedGames.push({
                        index: i,
                        game: tmpGame
                    });
                    if (tmpGame.player2 == -1) {
                        concat = app.Model.TournamentLogic.setScoreandGetChanges(i, 1, 0, tournament);
                        if (!concat) {
                            return false;
                        }
                        concat.shift();
                        changedGames = changedGames.concat(concat);
                    }
                } else if (tmpGame.source2 !== null && tmpGame.source2 !== "" && tmpGame.source2.game == gameIndex) {
                    if (tmpGame.source2.asWinner) {
                        tmpGame.player2 = app.Model.TournamentLogic.getWinner(tournament.gameList[gameIndex]);
                    } else {
                        tmpGame.player2 = app.Model.TournamentLogic.getLoser(tournament.gameList[gameIndex]);
                    }
                    if (tmpGame.player1 > -1 && tmpGame.player1 != null && tmpGame.player2 > -1 && tmpGame.player2 != null) {
                        tmpGame.editable = true;
                    }
                    changedGames.push({
                        index: i,
                        game: tmpGame
                    });
                    if (tmpGame.player1 == -1) {
                        concat = app.Model.TournamentLogic.setScoreandGetChanges(i, 0, 1, tournament);
                        if (concat === false) {
                            return false;
                        }
                        concat.shift();
                        changedGames = changedGames.concat(concat);
                    }
                }
            }
            console.log(tournament);
            app.Model.Data.setClientTournament(tournament);
            return changedGames;
        },

        /*
        Gibt Eine Liste aller Spiele in der angefragten Gewinnerrunde zurück.
        */
        getWinnersbracketRound: function(i, tournament) {
            tournament = tournament || app.Model.Data.getClientTournament();
            if (i <= tournament.winnersbracketRoundNumber) {
                var sumGames,
                    toGame,
                    fromGame,
                    tmp,
                    x;
                sumGames = Math.pow(2, tournament.winnersbracketRoundNumber - i);
                toGame = Math.pow(2, tournament.winnersbracketRoundNumber) * (1 - Math.pow(2, -i));
                fromGame = toGame - sumGames + 1;
                tmp = [];
                for (x = 0; x < sumGames; x++) {
                    tmp[x] = tournament.winnersbracket[x + fromGame - 1];
                }
                return tmp;
            } else {
                return null;
            }
        },

        /*
        Gibt Eine Liste aller Spiele in der angefragten Verliererrunde zurück.
        */
        getLosersbracketRound: function(i, tournament) {
            tournament = tournament || app.Model.Data.getClientTournament();
            if (i <= tournament.losersbracketRoundNumber) {
                var toGame = 0,
                    fromGame = 0,
                    x,
                    tmpX,
                    tmp;
                for (x = 1; x <= i; x++) {
                    tmpX = Math.floor((x + 1) / 2 + 1);
                    fromGame = toGame + 1;
                    toGame = toGame + Math.floor(tournament.fieldSize / Math.pow(2, tmpX));
                }
                tmp = [];
                for (x = 0; x < (toGame - fromGame + 1); x++) {
                    tmp[x] = tournament.losersbracket[x + fromGame - 1];
                }
                return tmp;
            } else {
                return null;
            }
        },

        /*
        Gibt den Verlierer des angefragten Spiels zurück
        */
        getLoser: function(game) {
            if (game.player1 === -1) {
                return game.player1;
            } else if (game.player2 === -1) {
                return game.player2;
            } else {
                if (game.scorePlayer1 < game.scorePlayer2) {
                    return game.player1;
                } else if (game.scorePlayer1 > game.scorePlayer2) {
                    return game.player2;
                } else {
                    return null;
                }
            }
        },

        /*
        Gibt den Gewinner des angefragten Spiels zurück
        */
        getWinner: function(game) {
            if (game.player1 === -1) {
                return game.player2;
            } else if (game.player2 === -1) {
                return game.player1;
            } else {
                if (game.scorePlayer1 > game.scorePlayer2) {
                    return game.player1;
                } else if (game.scorePlayer1 < game.scorePlayer2) {
                    return game.player2;
                } else {
                    return null;
                }
            }
        },

        /*
        Erstellt eine neues Turnier mit den angegebenen Teilnehmern und gibt das Turnierobjekt zurück.
        */
        createTournament: function(competitors, tournamentname) {
            //Benötigte Funktionen
            function Player(name) {
                this.name = name;
                //Und ggf noch weitere Eigenschaften
            }

            function Source(game, asWinner) {
                this.game = game;
                this.asWinner = asWinner;
            }

            function Game(player1, player2) {
                this.player1 = player1;
                this.player2 = player2;
                this.scorePlayer1 = -1;
                this.scorePlayer2 = -1;
                this.source1 = null;
                this.source2 = null;
                this.number = null;
                this.editable = true;
            }

            function allocationBye(games, numberBye, isTop) {
                if (games.length > 1 && numberBye > 0) {
                    var g1,
                        g2;
                    if (isTop) {
                        g1 = allocationBye(games.slice(0, games.length / 2), Math.ceil(numberBye / 2), true);
                        g2 = allocationBye(games.slice(games.length / 2, games.length), Math.floor(numberBye / 2), false);
                    } else {
                        g1 = allocationBye(games.slice(0, games.length / 2), Math.floor(numberBye / 2), true);
                        g2 = allocationBye(games.slice(games.length / 2, games.length), Math.ceil(numberBye / 2), false);
                    }
                    games = g1.concat(g2);
                } else if (numberBye > 0) {
                    games[0].editable = false;
                    games[0].player1 = -1;
                    games[0].scorePlayer2 = 1;
                    games[0].scorePlayer1 = 0;
                }
                return games;
            }

            if (tournamentname && competitors.length > 4) {
                //Verwendete Variablen
                var i,
                    numberBye,
                    tmpCompetitorsList = [],
                    games = [],
                    indexS1,
                    indexS2,
                    x,
                    roundX,
                    roundX1,
                    vrX1,
                    vrX,
                    gr,
                    tmpG,
                    //Objekte im Turnierobjekt
                    tournament = {
                        competitorsList: [],
                        counter: null,
                        fieldSize: null,
                        final: null,
                        gameList: [],
                        losersbracket: [],
                        losersbracketRoundNumber: null,
                        mainRound: [],
                        name: tournamentname,
                        winnersbracket: [],
                        winnersbracketRoundNumber: null
                    };

                //Vorberechnungen Feldgröße, Anzahl der freilose
                tournament.fieldSize = Math.pow(2, Math.ceil(Math.log(competitors.length) / Math.log(2)));
                numberBye = tournament.fieldSize - competitors.length;
                //Spieler anlegen
                for (i = 0; i < competitors.length; i++) {
                    tournament.competitorsList[tournament.competitorsList.length] = new Player(competitors[i]);
                }

                //Liste wird für spätere bearbeitungsschritte benötigt (Zufallsverteilung)
                for (i = 0; i < (tournament.competitorsList.length); i++) {
                    tmpCompetitorsList[i] = i;
                }

                //Spiele anlegen
                for (i = 0; i < tournament.fieldSize / 2; i++) {
                    games[i] = new Game(null, null);
                    games[i].number = i + 1;
                }

                //Verteilung der Freilose
                games = allocationBye(games, numberBye, true);

                //zufällige Verteilung der Teilnehmer auf die spiele
                for (i = 0; i < games.length; i++) {
                    //wenn spieler1 nicht freilos
                    if (games[i].player1 !== -1) {
                        //setze Spieler 1
                        indexS1 = Math.floor(Math.random() * tmpCompetitorsList.length);
                        games[i].player1 = tmpCompetitorsList[indexS1];
                        tmpCompetitorsList.splice(indexS1, 1);
                    }
                    //setze Spieler 2
                    indexS2 = Math.floor(Math.random() * tmpCompetitorsList.length);
                    games[i].player2 = tmpCompetitorsList[indexS2];
                    tmpCompetitorsList.splice(indexS2, 1);
                    //Übertragung in Spielliste und hauptrunde
                    tournament.gameList[tournament.gameList.length] = games[i];
                    tournament.mainRound[i] = tournament.gameList.length - 1;
                }
                //Spiele für Gewinnerrunde anlegen
                for (i = 0; i < (tournament.fieldSize / 2 - 1); i++) {
                    tmpG = new Game(null, null);
                    tmpG.editable = false;
                    tournament.gameList.push(tmpG);
                    tournament.winnersbracket[i] = tournament.gameList.length - 1;
                    tournament.gameList[tournament.winnersbracket[i]].number = i + 1;
                }
                //Anzahl der Runden berechnen
                tournament.winnersbracketRoundNumber = (Math.log((tournament.winnersbracket.length + 1) / 2) / Math.log(2) + 1);
                //Verteilung auf die gewinnerrunde
                //für die erste Gewinnerrunde
                for (i = 0; i < tournament.mainRound.length; i = i + 2) {
                    tournament.gameList[tournament.winnersbracket[i / 2]].source1 = new Source(tournament.mainRound[i], true);
                    tournament.gameList[tournament.winnersbracket[i / 2]].source2 = new Source(tournament.mainRound[i + 1], true);
                }
                //Für die folgenden Gewinnerrunden
                for (x = 1; x < tournament.winnersbracketRoundNumber; x++) {

                    roundX = app.Model.TournamentLogic.getWinnersbracketRound(x, tournament);
                    roundX1 = app.Model.TournamentLogic.getWinnersbracketRound(x + 1, tournament);
                    for (i = 0; i < roundX.length; i = i + 2) {
                        tournament.gameList[roundX1[i / 2]].source1 = new Source(roundX[i], true);
                        tournament.gameList[roundX1[i / 2]].source2 = new Source(roundX[i + 1], true);
                    }
                }
                //Spiele für verliererrunden anlegen
                for (i = 0; i < (tournament.fieldSize - 2); i++) {
                    tmpG = new Game(null, null);
                    tmpG.editable = false;
                    tournament.gameList.push(tmpG);
                    tournament.losersbracket[i] = tournament.gameList.length - 1;
                    tournament.gameList[tournament.losersbracket[i]].number = i + 1;
                }
                //Berechnung der Anzahl der Verliererrunden
                tournament.losersbracketRoundNumber = Math.floor(Math.log((tournament.losersbracket.length / 2 + 1) / 2) / Math.log(2) + 1) * 2;
                //Verteilung HR --> VR1
                for (i = 0; i < tournament.mainRound.length; i = i + 2) {
                    tournament.gameList[tournament.losersbracket[i / 2]].source1 = new Source(tournament.mainRound[i], false);
                    tournament.gameList[tournament.losersbracket[i / 2]].source2 = new Source(tournament.mainRound[i + 1], false);
                }
                //Verteilung VR/GR -- > VR
                for (x = 1; x < tournament.losersbracketRoundNumber; x++) {
                    if (x % 2 === 0) {
                        roundX = app.Model.TournamentLogic.getLosersbracketRound(x, tournament);
                        roundX1 = app.Model.TournamentLogic.getLosersbracketRound(x + 1, tournament);
                        for (i = 0; i < roundX.length; i = i + 2) {
                            tournament.gameList[roundX1[i / 2]].source1 = new Source(roundX[i], true);
                            tournament.gameList[roundX1[i / 2]].source2 = new Source(roundX[i + 1], true);
                        }
                    } else {
                        vrX1 = app.Model.TournamentLogic.getLosersbracketRound(x + 1, tournament);
                        vrX = app.Model.TournamentLogic.getLosersbracketRound(x, tournament);
                        gr = app.Model.TournamentLogic.getWinnersbracketRound((x + 1) / 2, tournament);
                        for (i = 0; i < vrX.length; i++) {
                            tournament.gameList[vrX1[i]].source1 = new Source(vrX[i], true);
                            tournament.gameList[vrX1[i]].source2 = new Source(gr[gr.length - 1 - i], false);
                        }
                    }
                }
                //Finale
                tournament.gameList.push(new Game(null, null));
                tournament.final = tournament.gameList.length - 1;
                tournament.gameList[tournament.final].editable = false;
                tournament.gameList[tournament.final].number = 1000;
                tournament.gameList[tournament.final].source1 = new Source(tournament.winnersbracket[tournament.winnersbracket.length - 1], true);
                tournament.gameList[tournament.final].source2 = new Source(tournament.losersbracket[tournament.losersbracket.length - 1], true);
                //Falls freilose dabei sind erste Zuteilung der "Gewinner" auf die nächste runde
                for (i = 0; i < tournament.gameList.length; i++) {
                    if (tournament.gameList[i].source1 !== null) {
                        if (tournament.gameList[i].source1.asWinner) {
                            tournament.gameList[i].player1 = app.Model.TournamentLogic.getWinner(tournament.gameList[tournament.gameList[i].source1.game]);
                        } else {
                            tournament.gameList[i].player1 = app.Model.TournamentLogic.getLoser(tournament.gameList[tournament.gameList[i].source1.game]);
                        }
                    }
                    if (tournament.gameList[i].player1 == -1) {
                        tournament.gameList[i].scorePlayer1 = 0;
                        tournament.gameList[i].scorePlayer2 = 1;
                    }
                    if (tournament.gameList[i].source2 !== null) {
                        if (tournament.gameList[i].source2.asWinner) {
                            tournament.gameList[i].player2 = app.Model.TournamentLogic.getWinner(tournament.gameList[tournament.gameList[i].source2.game]);
                        } else {
                            tournament.gameList[i].player2 = app.Model.TournamentLogic.getLoser(tournament.gameList[tournament.gameList[i].source2.game]);
                        }
                    }
                    if (tournament.gameList[i].player1 > -1 && tournament.gameList[i].player1 != null && tournament.gameList[i].player2 > -1 && tournament.gameList[i].player2 != null) {
                        tournament.gameList[i].editable = true;
                    }
                }
                console.log(tournament);
                return tournament;
            } else {
                return null;
            }
        },
    },

    /*
    Data stellt die Schnittstelle zur loakeln Datenhaltung dar.
    Es werden Funktionen bereitgestellt umd Daten lokal zu speichern und Abzurufen.
    */
    Data: {
        /*
        Initialisiert die lokale Datenhaltung.
        */
        init: function() {
            if (!sessionStorage['clientTournament'] && !sessionStorage['isAdmin']) {
                app.Model.Data.resetClientTournament();
            }
            sessionStorage['tournamentList'] = JSON.stringify([]);
        },

        /*
        Speichert das gegebene Turnier lokal
        */
        setClientTournament: function(tournament) {
            sessionStorage['clientTournament'] = JSON.stringify(tournament);
        },

        /*
        Gibt das lokal gespeicherte Turnier zurück.
        */
        getClientTournament: function() {
            return JSON.parse(sessionStorage['clientTournament']);
        },

        /*
        Speichert die gegebene TurnierListe lokal
        */
        setTournamentList: function(list) {
            sessionStorage['tournamentList'] = JSON.stringify(list);
        },

        /*
        Gibt die lokal gespeicherte TurnierListe zurück.
        */
        getTournamentList: function() {
            return JSON.parse(sessionStorage['tournamentList']);
        },

        /*
        Speichert die Rechte für das Aktuelle Turnier
        */
        setIsAdmin: function(isAdmin) {
            sessionStorage['isAdmin'] = JSON.stringify(isAdmin);
        },

        /*
        Gibt die Rechte für das Aktuelle Turnier zurück
        */
        getIsAdmin: function() {
            return JSON.parse(sessionStorage['isAdmin']);
        },

        /*
        Speichert die ID des aktuellen Turniers lokal
        */
        setTournamentID: function(tournamentID) {
            sessionStorage['tournamentID'] = JSON.stringify(tournamentID);
        },

        /*
        gibt die ID des aktuellen Turniers zurück
        */
        getTournamentID: function() {
            return JSON.parse(sessionStorage['tournamentID']);
        },

        /*
        Gibt eine einmalige ID zurück.
        */
        getUUID: function() {
            return device.uuid;
        },

        /*
        Setzt die Lokal gespeicherten Daten zurück
        */
        resetClientTournament: function() {
            sessionStorage['clientTournament'] = JSON.stringify(null);
            sessionStorage['isAdmin'] = JSON.stringify(false);
            sessionStorage['tournamentID'] = JSON.stringify(-1);
        },

        /*
        Pflegt änderungen in der Turnierliste ein und speichert sie
        */
        updateTournamentList: function(data) {
            var tList = app.Model.Data.getTournamentList()
            if (data.name) {
                tList.push({
                    _id: data.id,
                    tournament: {
                        name: data.name
                    }
                });
            } else {
                $.each(tList, function(index, val) {
                    if (val._id === data.id) {
                        tList.splice(index, 1);
                        return false;
                    }
                });
            }
            app.Model.Data.setTournamentList(tList);
        },

        /*
        Bereit die Daten für die tabellenansicht auf und speichert sie, um sie nur einmal berechnen zu müssen
        */
        createTableData: function() {
            try {
                var rounds = [],
                    tmpTournament = app.Model.Data.getClientTournament();

                rounds.push({
                    roundname: 'Hauptrunde',
                    games: getGamesArray(tmpTournament.mainRound)
                });

                for (var x = 1; x <= tmpTournament.losersbracketRoundNumber; x++) {
                    rounds.push({
                        roundname: 'Verliererrunde ' + x,
                        games: getGamesArray(app.Model.TournamentLogic.getLosersbracketRound(x, tmpTournament))
                    });
                    if (x <= tmpTournament.winnersbracketRoundNumber) {
                        rounds.push({
                            roundname: 'Gewinnerrunde ' + x,
                            games: getGamesArray(app.Model.TournamentLogic.getWinnersbracketRound(x, tmpTournament))
                        });
                    }
                }

                rounds.push({
                    roundname: 'Finale',
                    games: getGamesArray([tmpTournament.final])
                });
                app.Model.Data.tableData = rounds;

            } catch (err) {
                console.log(err);
            }

            function getGamesArray(roundArray) {
                var games = [];
                for (var i = 0; i < roundArray.length; i++) {
                    var tmpGame = tmpTournament.gameList[roundArray[i]];
                    games.push({
                        number: roundArray[i],
                        player1: getPlayerString(tmpGame, true),
                        player2: getPlayerString(tmpGame, false),
                        score1: tmpGame.scorePlayer1 == -1 ? 'N/A' : tmpGame.scorePlayer1,
                        score2: tmpGame.scorePlayer2 == -1 ? 'N/A' : tmpGame.scorePlayer2
                    });
                }
                return games;
            }

            function getPlayerString(game, isPlayer1) {
                var str;
                if (isPlayer1) {
                    if (game.player1 !== null && game.player1 !== "") {
                        str = game.player1 == -1 ? 'Freilos' : tmpTournament.competitorsList[game.player1].name;
                    } else {
                        str = (game.source1.asWinner ? 'Gewinner aus Spiel ' : 'Verlierer aus Spiel ') + (parseInt(game.source1.game) + 1);
                    }
                } else {
                    if (game.player2 !== null && game.player2 !== "") {
                        str = game.player2 == -1 ? 'Freilos' : tmpTournament.competitorsList[game.player2].name;
                    } else {
                        str = (game.source2.asWinner ? 'Gewinner aus Spiel ' : 'Verlierer aus Spiel ') + (parseInt(game.source2.game) + 1);
                    }
                }
                return str;
            }
        },


        /*
        Pflegt Änderungen im aktuellen Turnier ein und speichert sie
        */
        updateGames: function(changes) {
            if (app.Model.Data.getClientTournament() != null && app.Model.Data.getClientTournament() !== "") {
                var changedGame;
                while (changes.length > 0) {
                    changedGame = changes.pop();
                    var tmp = app.Model.Data.getClientTournament()
                    tmp.gameList[changedGame.index] = changedGame.game;
                    app.Model.Data.setClientTournament(tmp);
                }
            }
            app.Model.Data.createTableData();
        }
    }
};

/*
Der Router dient dazu die verschiedenen routen zu interpretieren und auf die korrekte Ansicht zu erzeugen.
*/
app.Router = Backbone.Router.extend({

    /*
    Routen werden defeniert und funktionen zum handeln zugewiesen.
    */
    routes: {
        "home": "navigateToHome",
        "create": "navigateToCreate",
        "table": "navigateToTable",
        "tree": "navigateToTree",
        "ranking": "navigateToRanking",
        "edit/:id": "navigateToEdit",
        "*path": "navigateToHome"
    },

    /*
    Navigiert zur Startseite
    Obere und untere Navigationsleisten werden angepasst.
    Der Hauptinhalt wird durch den Funktionsaufruf app.View.Home.init() ausgetauscht.
    */
    navigateToHome: function() {
        $('#wrapper').attr('data-tournamentView', 'false');
        app.View.Home.init();

        //Nav-Top bearbeiten
        $('#nav-top h1').html('Home');
        //Button auf der linken Seite ausblenden
        $('#btn-top-left').hide()
            .unbind();
        //Button auf der rechten seite zum erstellen
        $('#btn-top-right').show()
            .unbind()
            .removeClass('disabled-btn')
            .click(function() {
                app.router.navigate('create', {
                    trigger: true
                });
            })
            .html('<span class="glyphicon glyphicon-plus"></span>');

        //Nav-Bottom bearbeiten --> deaktivieren
        $('#nav-bottom').children().unbind()
            .removeClass('active-btn')
            .addClass('disabled-btn');

    },

    /*
    Navigiert zur Erstellen-Ansicht
    Obere und untere Navigationsleisten werden angepasst.
    Der Hauptinhalt wird durch den Funktionsaufruf app.View.Create.init() ausgetauscht.
    */
    navigateToCreate: function() {
        $('#wrapper').attr('data-tournamentView', 'false');
        //Wrapper austauschen
        app.View.Create.init();

        //Nav-Top bearbeiten
        $('#nav-top h1').html('Turnier erstellen');
        //Button auf der Linken seite zum zurück navigieren
        $('#btn-top-left').show()
            .unbind()
            .click(function() {
                app.router.navigate('home', {
                    trigger: true
                });
            })
            .html('<span class="glyphicon glyphicon-chevron-left"></span>');
        //Button rechts wird ausgeblendet
        $('#btn-top-right').hide()
            .removeClass('disabled-btn')
            .unbind();

        //Nav-Bottom bearbeiten
        $('#nav-bottom').children().unbind()
            .removeClass('active-btn')
            .addClass('disabled-btn');

    },

    /*
    Obere und untere Navigationsleisten werden für die Turnieransichten angepasst.
    */
    navigateToTournament: function() {
        if (app.Model.Data.getClientTournament() != null && app.Model.Data.getClientTournament() !== "") {
            $('#wrapper').attr('data-tournamentView', 'true');
            var name = app.Model.Data.getClientTournament().name;

            $('#nav-top h1').html(name || 'Turnier');
            $('#btn-top-left').show()
                .unbind()
                .click(app.Controller.leaveTournament)
                .html('<span class="glyphicon glyphicon-chevron-left"></span>');
            $('#btn-top-right').unbind();
            if (app.Model.Data.getIsAdmin()) {
                $('#btn-top-right').removeClass('disabled-btn')
                    .click(app.Controller.quitTournament)
                    .show()
                    .html('<span class="glyphicon glyphicon-off"></span>');
            } else {
                $('#btn-top-right').addClass('disabled-btn')
                    .hide();
            }

            //Nav-Bottom bearbeiten
            $('#nav-bottom').children().unbind()
                .removeClass('active-btn disabled-btn');
            $('#btn-tableView').click(function() {
                app.router.navigate('table', {
                    trigger: true
                });
            });
            $('#btn-treeView').click(function() {
                app.router.navigate('tree', {
                    trigger: true
                });
            });
            $('#btn-rankingView').click(function() {
                app.router.navigate('ranking', {
                    trigger: true
                });
            });
            if (app.Model.Data.getIsAdmin()) {
                $('#btn-editView').removeClass('disabled-btn')
                    .click(function() {
                        app.router.navigate('edit/-1', {
                            trigger: true
                        });
                    });
            } else {
                $('#btn-editView').addClass('disabled-btn');
            }
        }
    },

    /*
    Navigiert zur Tabellen-Ansicht
    Obere und untere Navigationsleisten werden angepasst durch navigateToTournament.
    Der Hauptinhalt wird durch den Funktionsaufruf app.View.Table.init() ausgetauscht.
    */
    navigateToTable: function() {
        if (app.Model.Data.getClientTournament != null) {
            if ($('#wrapper').attr('data-tournamentView') != 'true') {
                app.router.navigateToTournament();
            }
            //Wrapper austauschen
            app.View.Table.init();
            //Aktive  Seite in Nav-Bottom setzen
            $('#nav-bottom .active-btn').removeClass('active-btn');
            $('#btn-tableView').addClass('active-btn');
        } else {
            app.router.navigate('home', {
                trigger: true
            });
        }
    },

    /*
    Navigiert zur Baum-Ansicht
    Obere und untere Navigationsleisten werden angepasst durch navigateToTournament.
    Der Hauptinhalt wird durch den Funktionsaufruf app.View.Tree.init() ausgetauscht.
    */
    navigateToTree: function() {
        if (app.Model.Data.getClientTournament != null) {
            if ($('#wrapper').attr('data-tournamentView') != 'true') {
                app.router.navigateToTournament();
            }
            //Wrapper austauschen
            app.View.Tree.init();
            //Aktive  Seite in Nav-Bottom setzen
            $('#nav-bottom .active-btn').removeClass('active-btn');
            $('#btn-treeView').addClass('active-btn');
        } else {
            app.router.navigate('home', {
                trigger: true
            });
        }
    },

    /*
    Navigiert zur Ranfolgen-Ansicht
    Obere und untere Navigationsleisten werden angepasst durch navigateToTournament.
    Der Hauptinhalt wird durch den Funktionsaufruf app.View.Ranking.init() ausgetauscht.
    */
    navigateToRanking: function() {
        if (app.Model.Data.getClientTournament != null) {
            if ($('#wrapper').attr('data-tournamentView') != 'true') {
                app.router.navigateToTournament();
            }
            //Wrapper austauschen
            app.View.Ranking.init();
            //Aktive  Seite in Nav-Bottom setzen
            $('#nav-bottom .active-btn').removeClass('active-btn');
            $('#btn-rankingView').addClass('active-btn');
        } else {
            app.router.navigate('home', {
                trigger: true
            });
        }
    },

    /*
    Navigiert zur Bearbeiten-Ansicht
    Obere und untere Navigationsleisten werden angepasst.
    Der Hauptinhalt wird durch den Funktionsaufruf app.View.Edit.init() ausgetauscht.
    */
    navigateToEdit: function(gameIndex) {
        if (app.Model.Data.getClientTournament != null) {
            $('#wrapper').attr('data-tournamentView', 'false');
            app.View.Edit.init(gameIndex);
            //Nav-Top bearbeiten
            $('#nav-top h1').html('Ergebnis setzen');
            $('#btn-top-left').show()
                .unbind()
                .click(function() {
                    app.router.navigate('table', {
                        trigger: true
                    });
                })
                .html('<span class="glyphicon glyphicon-chevron-left"></span>');
            $('#btn-top-right').hide()
                .unbind();
            //Nav-Bottom bearbeiten
            $('#nav-bottom').children().unbind()
                .removeClass('active-btn');
            $('#btn-editView').addClass('active-btn');
            $('#btn-tableView').click(function() {
                app.router.navigate('table', {
                    trigger: true
                });
            });
            $('#btn-treeView').click(function() {
                app.router.navigate('tree', {
                    trigger: true
                });
            });
            $('#btn-rankingView').click(function() {
                app.router.navigate('ranking', {
                    trigger: true
                });
            });
        } else {
            app.router.navigate('home', {
                trigger: true
            });
        }
    }
});
